package com.dtranx.tools.licensecreate.utils;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Paint;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;

import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * 时间选择器
 *
 * @author tang
 * @since 2014/7/18
 */
@SuppressWarnings("serial")
public class Gqrq extends JPanel {

    public static void main(String[] args) {
        final JFrame frame = new JFrame("时间选择器");
        frame.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 20));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500, 500);
        frame.setLocationRelativeTo(null);

        final JTextField textField = new JTextField(10);
        frame.add(textField);

        final JButton buttonLeft = new JButton("选择日期(弹出的对话框以此按钮左对齐)");
        buttonLeft.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {

                Dimension dialogSize = new Dimension(400, 250);
                Point screen = buttonLeft.getLocationOnScreen();
                Point point = new Point(screen.x, screen.y + buttonLeft.getPreferredSize().height + 5);

                Gqrq dateChooser = new Gqrq();
                String selectedDate = dateChooser.showDateDialog(frame, point, dialogSize);
                if (dateChooser.isConfirm()) {
                    textField.setText(selectedDate);
                }
            }
        });
        frame.add(buttonLeft);

        final JButton buttonRight = new JButton("选择日期(弹出的对话框以此按钮右对齐)");
        buttonRight.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {

                Dimension dialogSize = new Dimension(400, 250);
                int x = dialogSize.width - buttonRight.getPreferredSize().width;
                Point screen = buttonRight.getLocationOnScreen();
                Point point = new Point(screen.x - x, screen.y + buttonRight.getPreferredSize().height + 5);

                Gqrq dateChooser = new Gqrq();
                String selectedDate = dateChooser.showDateDialog(frame, point, dialogSize);
                if (dateChooser.isConfirm()) {
                    textField.setText(selectedDate);
                }
            }
        });
        frame.add(buttonRight);

        frame.setVisible(true);
    }

    protected final int startYear;
    protected final int lastYear;

    protected final String[] weekStrings = {"日", "一", "二", "三", "四", "五", "六"};

    protected Color selectedColor = new Color(250, 100, 100);
    protected Color northColor = Color.decode("#f6f6f6"); // 控制条底色
    protected Color labelColor = new Color(55, 80, 80); // 年/月标签文字色
    protected Font labelFont = new Font("微软雅黑", Font.PLAIN, 14); // 年/月标签字体
    protected Color weekLabelColor = new Color(150, 50, 150); // 星期标签文字色
    protected Color weekendFontColor = new Color(100, 200, 100); // 周末文字色
    protected Color dateFontColor = Color.BLACK; // 日期文字色

    protected JDialog dialog;
    protected JSpinner yearSpinner;
    protected JSpinner monthSpinner;
    protected JButton[][] dayButtons = new JButton[6][7];
    protected ButtonGroup buttonGroup = new ButtonGroup();

    protected DateFormat format;
    protected Date date;
    protected String selectedDay;
    protected boolean isConfirm;

    public Gqrq() {
        this(new SimpleDateFormat("yyyy-MM-dd"));
    }

    public Gqrq(DateFormat format) {
        this(format, new Date());
    }

    public Gqrq(DateFormat format, Date date) {
        this(format, date, 1980, 2080);
    }

    public Gqrq(DateFormat format, Date date, int startYear, int lastYear) {
        this.date = date;
        this.format = format;
        this.startYear = startYear;
        this.lastYear = lastYear;
        selectedDay = getCalendar().get(Calendar.DAY_OF_MONTH) + "";

        setLayout(new BorderLayout());
        setBackground(Color.WHITE);

        JPanel northPanel = createNorthPanal();
        northPanel.setPreferredSize(new Dimension(0, 40));
        add(northPanel, BorderLayout.NORTH);

        JPanel centerPanel = createCenterPanal();
        add(centerPanel, BorderLayout.CENTER);

        JPanel southPanel = createSouthPanel();
        southPanel.setPreferredSize(new Dimension(0, 40));
        add(southPanel, java.awt.BorderLayout.SOUTH);

    }

    private JPanel createNorthPanal() {
        Calendar c = getCalendar();
        int currentYear = c.get(Calendar.YEAR);
        int currentMonth = c.get(Calendar.MONTH) + 1;

        JPanel northPanel = new JPanel();
        northPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 8));
        northPanel.setBackground(northColor);

        yearSpinner = new JSpinner(new SpinnerNumberModel(currentYear, startYear, lastYear, 1));
        yearSpinner.setEditor(new JSpinner.NumberEditor(yearSpinner, "####"));
        yearSpinner.setPreferredSize(new Dimension(60, 25));
        yearSpinner.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                updateDate(Calendar.YEAR, (Integer) yearSpinner.getValue());
            }
        });
        northPanel.add(yearSpinner);

        JLabel yearLabel = new JLabel("年");
        yearLabel.setForeground(labelColor);
        yearLabel.setFont(labelFont);
        northPanel.add(yearLabel);

        northPanel.add(Box.createHorizontalStrut(15));

        monthSpinner = new JSpinner(new SpinnerNumberModel(currentMonth, 1, 12, 1));
        monthSpinner.setEditor(new JSpinner.NumberEditor(monthSpinner, "##"));
        monthSpinner.setPreferredSize(new Dimension(60, 25));
        monthSpinner.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                updateDate(Calendar.MONTH, (Integer) monthSpinner.getValue() - 1);
            }
        });
        northPanel.add(monthSpinner);

        JLabel monthLabel = new JLabel("月");
        monthLabel.setForeground(labelColor);
        monthLabel.setFont(labelFont);
        northPanel.add(monthLabel);

        return northPanel;
    }

    private JPanel createCenterPanal() {

        JPanel centerPanel = new JPanel();
        // 设置固定字体，以免调用环境改变影响界面美观
        centerPanel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
        centerPanel.setLayout(new GridLayout(7, 7));
        centerPanel.setBackground(Color.WHITE);

        for (int i = 0; i < 7; i++) {
            RolloverBackgroundButton cell = new RolloverBackgroundButton(weekStrings[i]);
            cell.clearDefaultAttribute();
            cell.setHorizontalAlignment(JLabel.RIGHT);
            cell.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            cell.setNormalForeground(weekLabelColor);
            centerPanel.add(cell);
        }

        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 7; j++) {
                final RolloverBackgroundButton numberButton = new RolloverBackgroundButton("");
                numberButton.clearDefaultAttribute();
                numberButton.setHorizontalAlignment(SwingConstants.RIGHT);
                numberButton.setNormalForeground(dateFontColor);
                numberButton.setSelectedForeground(selectedColor);
                numberButton.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        if (numberButton.getText().length() == 0) {
                            return;
                        }

                        selectedDay = numberButton.getText();

                        updateDate(Calendar.DAY_OF_MONTH, Integer.parseInt(numberButton.getText()));

                        ComponentTool.clearButtonGroupSelected(buttonGroup);
                        numberButton.setSelected(true);
                        ComponentTool.updateButtonSelectedForeground(buttonGroup, selectedColor);
                    }
                });
                if (j == 0 || j == 6) {
                    numberButton.setNormalForeground(weekendFontColor);
                } else {
                    numberButton.setNormalForeground(dateFontColor);
                }
                dayButtons[i][j] = numberButton;
                centerPanel.add(numberButton);
                buttonGroup.add(numberButton);
            }
        }

        return centerPanel;
    }

    private JPanel createSouthPanel() {

        JPanel southPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 2));
        southPanel.setOpaque(false);

        JButton todayButton = new RolloverBackgroundButton("今天");
        todayButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                today();
            }
        });
        southPanel.add(todayButton);

        JButton cancelButton = new RolloverBackgroundButton("取消");
        cancelButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                cancel();
            }
        });
        southPanel.add(cancelButton);

        JButton confirmButton = new RolloverBackgroundButton("确定");
        confirmButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                confirm();
            }
        });
        southPanel.add(confirmButton);

        return southPanel;
    }

    /**
     * 显示日期选择对话框
     *
     * @param owner
     * @return
     */
    public String showDateDialog(Window owner) {
        return showDateDialog(owner, null);
    }

    public String showDateDialog(Window owner, Point dialogPoint) {
        return showDateDialog(owner, dialogPoint, new Dimension(400, 250));
    }

    /**
     * 显示日期选择对话框
     *
     * @param owner
     * @param dialogPoint
     * @return
     */
    public String showDateDialog(Window owner, Point dialogPoint, Dimension size) {
        if (dialog == null) {
            dialog = createDialog(owner, size);
        }
        dialog.setLocationRelativeTo(owner);
        if (dialogPoint != null) {
            dialog.setLocation(dialogPoint);
        }
        updateDayButtonsText();
        dialog.setVisible(true);
        return getDateText();
    }

    protected JDialog createDialog(Window owner, Dimension size) {
        JDialog dialog = new JDialog(owner, "日期时间选择") {
            public void setVisible(boolean b) {
                if (b) {// 此处先if还是先super顺序很重要
                    isConfirm = false;
                }
                super.setVisible(b);
            }
        };
        dialog.setModal(true);
        dialog.setSize(size);
        dialog.setContentPane(this);
        dialog.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                cancel();
            }
        });
        return dialog;
    }

    /**
     * 用户点击取消
     */
    protected void cancel() {
        isConfirm = false;
        dialog.setVisible(false);
    }

    /**
     * 用户点击今天
     */
    protected void today() {
        date = new Date();
        Calendar c = getCalendar();
        yearSpinner.setValue(c.get(Calendar.YEAR));
        monthSpinner.setValue(c.get(Calendar.MONTH) + 1);
        selectedDay = c.get(Calendar.DAY_OF_MONTH) + "";
        setDate(c.getTime());
        updateDayButtonsText();
    }

    /**
     * 用户点击确定
     */
    protected void confirm() {
        isConfirm = true;
        dialog.setVisible(false);
    }

    protected void updateDate(int type, int value) {

        Calendar c = getCalendar();

        if (type == Calendar.MONTH) {// 处理选择的天数超出月份最大的天数情况
            int day = c.get(Calendar.DAY_OF_MONTH);
            c.set(Calendar.DAY_OF_MONTH, 1);
            c.set(type, value);
            int maxMonth_to = c.getActualMaximum(Calendar.DAY_OF_MONTH);
            if (Integer.parseInt(selectedDay) <= maxMonth_to) {// 如果当前月份所选择的天数小于即将更新的月份的最大天数
                c.set(Calendar.DAY_OF_MONTH, day);// 还原天数
            } else {// 否则
                selectedDay = "1";
            }
        } else {
            c.set(type, value);
        }

        setDate(c.getTime());

        if (type != Calendar.DAY_OF_MONTH) {
            updateDayButtonsText();
        }
    }

    protected void updateDayButtonsText() {

        Calendar c = getCalendar();
        c.set(Calendar.DAY_OF_MONTH, 1);

        int maxDayNo = c.getActualMaximum(Calendar.DAY_OF_MONTH);
        int dayNo = 2 - c.get(Calendar.DAY_OF_WEEK);

        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 7; j++) {
                String s = "";
                if (dayNo >= 1 && dayNo <= maxDayNo) {
                    s = String.valueOf(dayNo);
                }
                dayButtons[i][j].setText(s);
                if (s.equals(selectedDay)) {
                    ComponentTool.clearButtonGroupSelected(buttonGroup);
                    dayButtons[i][j].setSelected(true);
                    ComponentTool.updateButtonSelectedForeground(buttonGroup, selectedColor);
                }
                dayNo++;
            }
        }
    }

    public Dimension getDialogSize() {
        return dialog.getSize();
    }

    protected Calendar getCalendar() {
        Calendar result = Calendar.getInstance();
        result.setTime(getDate());
        return result;
    }

    /**
     * 用户是否点击确定
     *
     * @return
     */
    public boolean isConfirm() {
        return isConfirm;
    }

    /**
     * 获取选择的时间字符串
     *
     * @return
     */
    public String getDateText() {
        return format.format(getDate());
    }

    /**
     * 设置默认的时间
     *
     * @param date
     */
    public void setDate(Date date) {
        this.date = date;
    }

    /**
     * 获取选择的时间
     *
     * @return
     */
    public Date getDate() {
        return date;
    }

    //

    public static class ComponentTool {

        public static void updateButtonSelectedForeground(ButtonGroup buttonGroup, Color selectedColor) {
            for (Enumeration<AbstractButton> enumBtn = buttonGroup.getElements(); enumBtn.hasMoreElements(); ) {
                RolloverBackgroundButton button = (RolloverBackgroundButton) enumBtn.nextElement();
                if (!button.isSelected()) {
                    button.setSelectedForeground(null);
                } else {
                    button.setSelectedForeground(selectedColor);
                }
                button.repaint();
            }
        }

        public static void clearButtonGroupSelected(ButtonGroup buttonGroup) {
            for (Enumeration<AbstractButton> button = buttonGroup.getElements(); button.hasMoreElements(); ) {
                button.nextElement().setSelected(false);
            }
        }
    }

    /**
     * 鼠标悬浮和按下以及选中时能切换背景颜色/边框颜色/前景颜色的Button
     *
     * @author tang
     * @since 2014/8/23
     */
    public static class RolloverBackgroundButton extends JButton {

        protected Color normalBackground;// 默认无状态时背景颜色,此属性父类中已定义(background)
        protected Color pressedBackground;// 鼠标按下时背景颜色
        protected Color rolloverBackground;// 鼠标悬浮时背景颜色
        protected Color selectedBackground;// 选中时背景颜色

        protected Color normalBorderColor;// 默认无状态时边框颜色
        protected Color pressedBorderColor;// 鼠标按下时边框颜色
        protected Color rolloverBorderColor;// 鼠标悬浮时边框颜色
        protected Color selectedBorderColor;// 选中时边框颜色

        protected Color normalForeground;// 默认时前景颜色
        protected Color pressedForeground;// 鼠标按下时前景颜色
        protected Color rolloverForeground;// 鼠标悬浮时前景颜色
        protected Color selectedForeground;// 选中时前景颜色

        {
            initRolloverButton();
        }

        public RolloverBackgroundButton() {
        }

        public RolloverBackgroundButton(Icon icon) {
            super(icon);
        }

        public RolloverBackgroundButton(String text, Icon icon) {
            super(text, icon);
        }

        public RolloverBackgroundButton(String text) {
            super(text);
        }

        public RolloverBackgroundButton(Action a) {
            super(a);
        }

        private void initRolloverButton() {
            setRolloverEnabled(true);
            setBorderPainted(false);
            setContentAreaFilled(false);
            setFocusPainted(false);
            setFont(new Font(Font.DIALOG, Font.PLAIN, 14));

            setNormalBackground(new Color(216, 216, 216));
            setPressedBackground(new Color(216, 216, 216, 100));
            setNormalBorderColor(new Color(174, 174, 174));
            setRolloverBorderColor(new Color(95, 205, 245));
            setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        }

        @Override
        public void paint(Graphics g) {
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            Paint oldPaint = g2d.getPaint();
            if (isSelected() && selectedBackground != null) {// 选中时
                g2d.setPaint(selectedBackground);
                g2d.fillRect(0, 0, getWidth(), getHeight());// 背景
            } else if (getModel().isPressed() && pressedBackground != null) {// 鼠标按下时
                g2d.setPaint(pressedBackground);
                g2d.fillRect(0, 0, getWidth(), getHeight());// 背景
            } else if (getModel().isRollover() && rolloverBackground != null) {// 鼠标悬浮时
                g2d.setPaint(rolloverBackground);
                g2d.fillRect(0, 0, getWidth(), getHeight());// 背景
            } else if (normalBackground != null) {// 默认无状态时
                g2d.setPaint(normalBackground);
                g2d.fillRect(0, 0, getWidth(), getHeight());// 背景
            }
            g2d.setPaint(oldPaint);

            if (isSelected() && selectedForeground != null) {// 选中时
                setForeground(selectedForeground);
            } else if (getModel().isPressed() && pressedForeground != null) {// 鼠标按下时
                setForeground(pressedForeground);
            } else if (getModel().isRollover() && rolloverForeground != null) {// 鼠标悬浮时
                setForeground(rolloverForeground);
            } else if (normalForeground != null) {// 默认无状态时
                setForeground(normalForeground);
            }

            super.paint(g2d);

            if (isSelected() && selectedBorderColor != null) {// 选中时
                g2d.setPaint(selectedBorderColor);
                g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);// 边框
            } else if (getModel().isPressed() && pressedBorderColor != null) {// 鼠标按下时
                g2d.setPaint(pressedBorderColor);
                g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);// 边框
            } else if (getModel().isRollover() && rolloverBorderColor != null) {// 鼠标悬浮时
                g2d.setPaint(rolloverBorderColor);
                g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);// 边框
            } else if (normalBorderColor != null) {// 默认无状态时
                g2d.setPaint(normalBorderColor);
                g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);// 边框
            }
            g2d.setPaint(oldPaint);
        }

        /**
         * 清空设置的默认属性值：<br>
         * <p>
         * setNormalBackground(null);<br>
         * setPressedBackground(null); <br>
         * setNormalBorderColor(null); <br>
         * setRolloverBorderColor(null);
         */
        public void clearDefaultAttribute() {
            setNormalBackground(null);
            setPressedBackground(null);
            setNormalBorderColor(null);
            setRolloverBorderColor(null);
        }

        public Color getNormalBackground() {
            return normalBackground;
        }

        public void setNormalBackground(Color normalBackground) {
            this.normalBackground = normalBackground;
        }

        public Color getPressedBackground() {
            return pressedBackground;
        }

        public void setPressedBackground(Color pressedBackground) {
            this.pressedBackground = pressedBackground;
        }

        public Color getRolloverBackground() {
            return rolloverBackground;
        }

        public void setRolloverBackground(Color rolloverBackground) {
            this.rolloverBackground = rolloverBackground;
        }

        public Color getNormalBorderColor() {
            return normalBorderColor;
        }

        public void setNormalBorderColor(Color normalBorderColor) {
            this.normalBorderColor = normalBorderColor;
        }

        public Color getPressedBorderColor() {
            return pressedBorderColor;
        }

        public void setPressedBorderColor(Color pressedBorderColor) {
            this.pressedBorderColor = pressedBorderColor;
        }

        public Color getRolloverBorderColor() {
            return rolloverBorderColor;
        }

        public void setRolloverBorderColor(Color rolloverBorderColor) {
            this.rolloverBorderColor = rolloverBorderColor;
        }

        public Color getPressedForeground() {
            return pressedForeground;
        }

        public void setPressedForeground(Color pressedForeground) {
            this.pressedForeground = pressedForeground;
        }

        public Color getRolloverForeground() {
            return rolloverForeground;
        }

        public void setRolloverForeground(Color rolloverForeground) {
            this.rolloverForeground = rolloverForeground;
        }

        public Color getNormalForeground() {
            return normalForeground;
        }

        public void setNormalForeground(Color normalForeground) {
            this.normalForeground = normalForeground;
        }

        public Color getSelectedBackground() {
            return selectedBackground;
        }

        public void setSelectedBackground(Color selectedBackground) {
            this.selectedBackground = selectedBackground;
        }

        public Color getSelectedBorderColor() {
            return selectedBorderColor;
        }

        public void setSelectedBorderColor(Color selectedBorderColor) {
            this.selectedBorderColor = selectedBorderColor;
        }

        public Color getSelectedForeground() {
            return selectedForeground;
        }

        public void setSelectedForeground(Color selectedForeground) {
            this.selectedForeground = selectedForeground;
        }
    }

}
